package ru.spb.osll.myfit.wikiverifier;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import ru.spb.osll.myfit.common.Page;
import ru.spb.osll.myfit.common.Table;
import ru.spb.osll.myfit.common.TableCell;
import ru.spb.osll.myfit.common.TableStyle;
import ru.spb.osll.myfit.server.parser.TableUtils;
import ru.spb.osll.myfit.wikiverifier.result.PageVerificationResult;
import ru.spb.osll.myfit.wikiverifier.result.TableVerificationResult;
import ru.spb.osll.myfit.wikiverifier.result.VerificationResultType;
import ru.spb.osll.myfit.wikiverifier.verifier.DoFixtureVerifier;
import ru.spb.osll.myfit.wikiverifier.verifier.OneLineFixtureVerifier;
import ru.spb.osll.myfit.wikiverifier.verifier.SetUpFixtureVerifier;
import ru.spb.osll.myfit.wikiverifier.verifier.TableVerifier;
import util.GracefulNamer;

public class WikiVerifier {
	private HashMap<TableStyle, TableVerifier> m_verifiers;
	private SuggestionProvider m_suggestionProvider;
	Map<String, Class<?>> m_fixtures;

	public WikiVerifier(List<Table> templates, Map<String, Class<?>> fixtures) {
		m_verifiers = new HashMap<TableStyle, TableVerifier>();
		m_verifiers.put(TableStyle.ONE_LINE_FIXTIRE, new OneLineFixtureVerifier(
				fixtures));
		m_verifiers.put(TableStyle.DO_FIXTURE, new DoFixtureVerifier(fixtures));
		m_verifiers.put(TableStyle.SETUP_FIXTURE, new SetUpFixtureVerifier(
				fixtures));
		m_suggestionProvider = new SuggestionProvider(templates);
		m_fixtures = fixtures;
	}

	public PageVerificationResult verifyPage(Page page, boolean makeSuggestion) {
		PageVerificationResult result = new PageVerificationResult();

		for (int i = 0; i < page.countPageElements(); i++) {
			Table table = (Table) page.getElement(i);
			TableVerificationResult tableResult = verifyTable(table);
			if (tableResult.getResult() != VerificationResultType.OK
					&& makeSuggestion) {
				m_suggestionProvider.provideSuggestion(tableResult);
			}
			result.addTableResult(tableResult);
		}

		return result;
	}

	private TableVerificationResult verifyTable(Table table) {

		try {
			if (table.getStyle() == TableStyle.UNKNOWN_FIXTURE) {
				TableStyle tableStyle = TableUtils.getTableStyle(getFixtureClass(table));
				table.setStyle(tableStyle);
			}

			if (!m_verifiers.containsKey(table.getStyle())) {
				throw new WikiVerifierException("Table style "
						+ table.getStyle() + " not supported");
			}

			return m_verifiers.get(table.getStyle()).verifyTable(table);

		} catch (WikiVerifierException e) {
			return new TableVerificationResult(VerificationResultType.FAILURE,
					table, e);
		}
	}

	private Class<?> getFixtureClass(Table table) {
		Iterator<Vector<TableCell>> tableIter = table.getData().iterator();

		if (!tableIter.hasNext()) {
			return null;
		}

		Vector<TableCell> line = tableIter.next();
		String className = getClassName(line);
		if (m_fixtures.containsKey(className + "Fixture")) {
			className = className + "Fixture";
		}

		if (!m_fixtures.containsKey(className)) {
			return null;
		}

		return m_fixtures.get(className);
	}

	private String getClassName(Vector<TableCell> tableLine) {
		return GracefulNamer.disgrace(tableLine.get(0).getText());
	}

}
